package cn.stimd.spring.context.annotation;

import cn.stimd.spring.beans.factory.annotation.AnnotatedBeanDefinition;
import cn.stimd.spring.beans.factory.config.BeanDefinition;
import cn.stimd.spring.beans.factory.support.AbstractBeanDefinition;
import cn.stimd.spring.context.stereotype.Component;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.StandardAnnotationMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;

import java.io.IOException;
import java.util.HashSet;
import java.util.Set;

/**
 * Created by Stimd
 * 项目地址：https://gitee.com/stimd/spring-wheel
 * 公众号：Java编程探微
 */
public class ConfigurationClassUtils {
    private static final String CONFIGURATION_CLASS_FULL = "full";      //Full模式
    private static final String CONFIGURATION_CLASS_LITE = "lite";      //Lite模式
    private static final String CONFIGURATION_CLASS_ATTRIBUTE = "configurationClass";
    private static final Set<String> candidateIndicators = new HashSet<>(4);

    static {
        candidateIndicators.add(Component.class.getName());
        candidateIndicators.add(ComponentScan.class.getName());
//        candidateIndicators.add(Import.class.getName());
    }


    /**
     * 检查是否为Configuration配置类
     */
    public static boolean checkConfigurationClassCandidate(BeanDefinition beanDef, MetadataReaderFactory factory) {
        //跳过通过BeanMethod创建的实例
        String className = beanDef.getBeanClassName();
        if (className == null || beanDef.getFactoryMethodName() != null) {
            return false;
        }

        //1. 获取Bean上的注解元数据
        AnnotationMetadata metadata;
        //检查使用注解声明的Bean
        if (beanDef instanceof AnnotatedBeanDefinition &&
                className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())) {
            metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata();
        }
        //如果已经解析了Bean的类型，则通过Class来创建元数据
        else if (beanDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) beanDef).hasBeanClass()) {
            Class<?> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass();
            metadata = new StandardAnnotationMetadata(beanClass, true);
        }
        //通过全限定类名生成元数据
        else {
            try {
                MetadataReader metadataReader = factory.getMetadataReader(className);
                metadata = metadataReader.getAnnotationMetadata();
            }
            catch (IOException ex) {
                return false;
            }
        }

        //2. 根据注解信息标记BeanDefinition是Full模式还是Lite模式
        if (isFullConfigurationCandidate(metadata)) {
            beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
        }
        else if (isLiteConfigurationCandidate(metadata)) {
            beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
        }
        else {
            return false;
        }
        return true;
    }


    public static boolean isConfigurationCandidate(AnnotationMetadata metadata) {
        return (isFullConfigurationCandidate(metadata) || isLiteConfigurationCandidate(metadata));
    }


    //使用@Configuration声明类，则认为是Full模式的配置类
    public static boolean isFullConfigurationCandidate(AnnotationMetadata metadata) {
        return metadata.isAnnotated(Configuration.class.getName());
    }


    //使用@Component、@ComponentScan、@Import声明类，或者@Bean声明方法，则认为是Lite模式的配置类
    public static boolean isLiteConfigurationCandidate(AnnotationMetadata metadata) {
        if (metadata.isInterface()) {
            return false;
        }

        for (String indicator : candidateIndicators) {
            if (metadata.isAnnotated(indicator)) {
                return true;
            }
        }

//        try {
//            return metadata.hasAnnotatedMethods(Bean.class.getName());
//        }
//        catch (Throwable ex) {
//            return false;
//        }
        return false;
    }
}
